home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Languguage OS 2
/
Languguage OS II Version 10-94 (Knowledge Media)(1994).ISO
/
language
/
ici
/
ici.cpi
/
cfunc.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-10-27
|
47KB
|
2,552 lines
#include "exec.h"
#include "func.h"
#include "str.h"
#include "int.h"
#include "float.h"
#include "struct.h"
#include "set.h"
#include "op.h"
#include "ptr.h"
#include "buf.h"
#include "file.h"
#include "re.h"
#include "null.h"
#include "parse.h"
#include "mem.h"
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#ifndef NOWAITFOR
/*
* For select() for waitfor().
*/
#include <sys/types.h>
#ifdef BSD
#include <sys/time.h>
#else
# ifdef mips
# include <bsd/sys/types.h>
# include <bsd/sys/time.h>
# else
# ifdef hpux
# include <time.h>
# else
# ifndef _R3000
# include <sys/select.h>
# include <sys/times.h>
# endif
# endif
# endif
# define bzero(p,n) (memset((p), 0, (n)))
# endif
#endif
#if defined(sun) && defined(__GNUC__) || !__STDC__
extern int fgetc();
#endif
/*
* typecheck(argspec, &arg1, &arg2...)
*
* Check ICI/C function argument types and translate into normal C data types.
* The argspec is a character string. Each character corresponds to
* an actual argument to the ICI function which will (may) be assigned
* through the corresponding pointer taken from the subsequent arguments.
* Any detected type mismatches result in a non-zero return. If all types
* match, all assignments will be made and zero will be returned.
*
* The argspec key letters and their meaning are:
*
* o Any ICI object is required in the actuals, the corresponding pointer
* must be a pointer to a (object_t *); which will be set to the actual
* argument.
* p An ICI ptr object is required in the actuals, then as for o.
* d An ICI struct object is required in the actuals, then as for o.
* a An ICI array object is required in the actuals, then as for o.
* u An ICI file object is required in the actuals, then as for o.
* i An ICI int object is required in the actuals, the value of this int
* will be stored through the corresponding pointer which must be
* a (long *).
* f An ICI float object is required in the actuals, the value of this float
* will be stored through the corresponding pointer which must be
* a (double *).
* n An ICI float or int object is required in the actuals, the value of
* this float or int will be stored through the corresponding pointer
* which must be a (double *).
* s An ICI string object is required in the actuals, the corresponding
* pointer must be a (char **). A pointer to the raw characters of
* the string will be stored through this (this will be '\0' terminated
* by virtue of all ICI strings having a gratuitous '\0' just past
* their real end).
* - The acutal parameter at this position is skipped, but it must be
* present.
* * All remaining actual parametes are ignored (even if there aren't any).
*
* The capitalisation of any of the alphabetic key letters above changes
* their meaning. The acutal must be an ICI ptr type. The value this
* pointer points to is taken to be the value which the above descriptions
* concern themselves with (i.e. in place of the raw actual parameter).
*
* There must be exactly as many actual arguments as key letters unless
* the last key letter is a *.
*
* Error returns have the usual ICI error conventions.
*/
int
typecheck(char *types, ...)
{
va_list va;
register object_t **ap; /* Argument pointer. */
register int nargs;
register int i;
char *ptr; /* Subsequent things from va_alist. */
register int tcode;
register object_t *o;
va_start(va, types);
nargs = NARGS();
ap = ARGS();
for (i = 0; types[i] != '\0'; ++i, --ap)
{
if (types[i] == '*')
{
va_end(va);
return 0;
}
if (i == nargs)
{
va_end(va);
return argcount(strlen(types));
}
if ((tcode = types[i]) == '-')
continue;
ptr = va_arg(va, char *);
if (tcode >= 'A' && tcode <= 'Z')
{
if (!isptr(*ap))
goto fail;
if ((o = fetch(*ap, objof(o_zero))) == NULL)
goto fail;
tcode += 'a' - 'A';
}
else
{
o = *ap;
}
switch (tcode)
{
case 'o': /* Any object. */
*(object_t **)ptr = o;
break;
case 'p': /* Any pointer. */
if (!isptr(o))
goto fail;
*(ptr_t **)ptr = ptrof(o);
break;
case 'i': /* An int -> int. */
if (!isint(o))
goto fail;
*(long *)ptr = intof(o)->i_value;
break;
case 's': /* A string -> (char *). */
if (!isstring(o))
goto fail;
*(char **)ptr = stringof(o)->s_chars;
break;
case 'f': /* A float -> double. */
if (!isfloat(o))
goto fail;
*(double *)ptr = floatof(o)->f_value;
break;
case 'n': /* A number, int or float -> double. */
if (isint(o))
*(double *)ptr = intof(o)->i_value;
else if (isfloat(o))
*(double *)ptr = floatof(o)->f_value;
else
goto fail;
break;
case 'd': /* A struct ("dict") -> (struct_t *). */
if (!isstruct(o))
goto fail;
*(struct_t **)ptr = structof(o);
break;
case 'a': /* An array -> (array_t *). */
if (!isarray(o))
goto fail;
*(array_t **)ptr = arrayof(o);
break;
case 'u': /* A file -> (file_t *). */
if (!isfile(o))
goto fail;
*(file_t **)ptr = fileof(o);
break;
case 'r': /* A regular expression -> (regexpr_t *). */
if (!isregexp(o))
goto fail;
*(regexp_t **)ptr = regexpof(o);
break;
}
}
va_end(va);
if (i != nargs)
return argcount(i);
return 0;
fail:
return argerror(i);
}
/*
* retcheck(retspec, &arg1, &arg2...)
*
* Perform storage of values through pointers in the actual arguments to
* an ICI/C function.
*
* The retspec is a character string consisting of key letters which
* correspond to actual arguments of the current ICI/C function.
* Each of the characters in the retspec has the following meaning.
*
* o The actual argument must be a ptr, the corresponding pointer is
* assumed to be an (object_t **). The location indicated by the
* ptr object is updated with the (object_t *).
* d
* a
* u Likwise for types as per typecheck() above.
* ...
* - The acutal argument is skipped.
* * ...
*/
int
retcheck(char *types, ...)
{
va_list va;
register int i;
register int nargs;
register object_t **ap;
char *ptr;
register int tcode;
register object_t *o;
register object_t *s;
va_start(va, types);
nargs = NARGS();
ap = ARGS();
for (i = 0; types[i] != '\0'; ++i, --ap)
{
if ((tcode = types[i]) == '*')
{
va_end(va);
return 0;
}
if (i == nargs)
{
va_end(va);
return argcount(strlen(types));
}
if (tcode == '-')
continue;
o = *ap;
if (!isptr(o))
goto fail;
ptr = va_arg(va, char *);
switch (tcode)
{
case 'o': /* Any object. */
*(object_t **)ptr = o;
break;
case 'p': /* Any pointer. */
if (!isptr(o))
goto fail;
*(ptr_t **)ptr = ptrof(o);
break;
case 'i':
if ((s = objof(new_int(*(long *)ptr))) == NULL)
goto ret1;
if (assign(o, objof(o_zero), s))
goto ret1;
loose(s);
break;
case 's':
if ((s = objof(new_cname(*(char **)ptr))) == NULL)
goto ret1;
if (assign(o, objof(o_zero), s))
goto ret1;
loose(s);
break;
case 'f':
if ((s = objof(new_float(*(double *)ptr))) == NULL)
goto ret1;
if (assign(o, objof(o_zero), s))
goto ret1;
loose(s);
break;
case 'd':
if (!isstruct(o))
goto fail;
*(struct_t **)ptr = structof(o);
break;
case 'a':
if (!isarray(o))
goto fail;
*(array_t **)ptr = arrayof(o);
break;
case 'u':
if (!isfile(o))
goto fail;
*(file_t **)ptr = fileof(o);
break;
case '*':
return 0;
}
}
va_end(va);
if (i != nargs)
return argcount(i);
return 0;
ret1:
va_end(va);
return 1;
fail:
va_end(va);
return argerror(i);
}
int
argerror(i)
int i;
{
char n[30];
sprintf(buf, "argument %d of %s() incorrectly supplied as %s",
i + 1,
cfuncof(o_top[-1])->cf_name,
objname(n, ARG(i)));
error = buf;
return 1;
}
int
argcount(n)
int n;
{
sprintf(buf, "%d arguments given to %s, but it takes %d",
NARGS(), cfuncof(o_top[-1])->cf_name, n);
error = buf;
return 1;
}
/*
* General way out of intrinsic functions, but only if the object is non-loose.
* Also allows NULL and does the error return.
*/
int
obj_ret(o)
object_t *o;
{
if (o == NULL)
return 1;
o_top -= NARGS();
o_top[-1] = o;
loose(o);
--x_top;
return 0;
}
/*
* Return method for loose objects out of intrinsic functions.
*/
int
loose_ret(o)
object_t *o;
{
o_top -= NARGS();
o_top[-1] = o;
--x_top;
return 0;
}
int
int_ret(ret)
long ret;
{
return obj_ret(objof(new_int(ret)));
}
int
str_ret(str)
char *str;
{
return obj_ret(objof(new_cname(str)));
}
file_t *
need_stdin()
{
file_t *f;
static string_t *string_stdin;
if (need_string(&string_stdin, "stdin"))
return NULL;
f = fileof(fetch(v_top[-1], string_stdin));
if (!isfile(f))
{
error = "stdin is not a file";
return NULL;
}
return f;
}
file_t *
need_stdout()
{
file_t *f;
static string_t *string_stdout;
if (need_string(&string_stdout, "stdout"))
return NULL;
f = fileof(fetch(v_top[-1], string_stdout));
if (!isfile(f))
{
error = "stdout is not a file";
return NULL;
}
return f;
}
#ifndef NOMATH
#if !__STDC__
# ifdef sun
/*
* Math exception handler for SVID compliant systems. We just set errno
* to the appropriate value and return non-zero. This stops the output
* of a message to stderr and allows normal error handling to control
* the behaviour.
*/
int
matherr(exc)
struct exception *exc;
{
switch (exc->type)
{
case DOMAIN:
case SING:
errno = EDOM;
break;
case OVERFLOW:
case UNDERFLOW:
errno = ERANGE;
break;
}
return 1;
}
# endif
#endif
/*
* For any C functions that return a double and take 0, 1, or 2 doubles as
* arguments.
*/
int
f_math()
{
double av[2];
double r;
if (typecheck(CF_ARG2() + 2, &av[0], &av[1]))
return 1;
errno = 0;
r = (*(double (*)())CF_ARG1())(av[0], av[1]);
if (errno != 0)
{
error = syserr();
return 1;
}
return obj_ret(objof(new_float(r)));
}
#endif
STATIC int
f_struct()
{
register object_t **o;
register int nargs;
register struct_t *s;
register struct_t *super;
nargs = NARGS();
o = ARGS();
super = NULL;
if (nargs & 1)
{
if (!(isstruct(objof(super = structof(*o)))))
return argerror(0);
--nargs;
--o;
}
if ((s = new_struct()) == NULL)
return 1;
for (; nargs >= 2; nargs -= 2, o -= 2)
{
if (assign(s, o[0], o[-1]))
{
loose(s);
return 1;
}
}
s->s_super = super;
return obj_ret(objof(s));
}
STATIC int
f_set()
{
register int nargs;
register set_t *s;
register object_t **o;
if ((s = new_set()) == NULL)
return 1;
for (nargs = NARGS(), o = ARGS(); nargs > 0; --nargs, --o)
{
if (assign(s, *o, objof(o_one)))
{
loose(s);
return 1;
}
}
return obj_ret(objof(s));
}
STATIC int
f_array()
{
register int nargs;
register array_t *a;
register object_t **o;
if ((a = new_array()) == NULL)
return 1;
nargs = NARGS();
if (pushcheck(a, nargs))
return 1;
for (o = ARGS(); nargs > 0; --nargs)
*a->a_top++ = *o--;
return obj_ret(objof(a));
}
STATIC int
f_keys()
{
struct_t *s;
register array_t *k;
register slot_t *sl;
if (typecheck("d", &s))
return 1;
if ((k = new_array()) == NULL)
return 1;
if (pushcheck(k, s->s_nels))
{
loose(k);
return 1;
}
for (sl = s->s_slots; sl < s->s_slots + s->s_nslots; ++sl)
{
if (sl->sl_key != NULL)
*k->a_top++ = sl->sl_key;
}
return obj_ret(objof(k));
}
STATIC int
f_copy()
{
if (NARGS() != 1)
return argcount(1);
return obj_ret(copy(ARG(0)));
}
STATIC int
f_regexp()
{
char *s;
extern regexp_t *new_regexp();
if (typecheck("s", &s))
return 1;
return obj_ret(objof(new_regexp(s)));
}
STATIC int
f_typeof()
{
if (NARGS() != 1)
return argcount(1);
return str_ret(ARG(0)->o_type->t_name);
}
STATIC int
f_nels()
{
register object_t *o;
long size;
if (NARGS() != 1)
return argcount(1);
o = ARG(0);
if (isstring(o))
size = stringof(o)->s_nchars;
else if (isarray(o))
size = arrayof(o)->a_top - arrayof(o)->a_base;
else if (isstruct(o))
size = structof(o)->s_nels;
else if (isset(o))
size = setof(o)->s_nels;
else if (ismem(o))
size = memof(o)->m_length;
else
size = 1;
return int_ret(size);
}
STATIC int
f_int()
{
register object_t *o;
register long v;
#ifndef __STDC__
extern long strtol();
#endif
if (NARGS() != 1)
return argcount(1);
o = ARG(0);
if (isint(o))
return loose_ret(o);
else if (isstring(o))
v = strtol(stringof(o)->s_chars, NULL, 0);
else if (isfloat(o))
v = (long)floatof(o)->f_value;
else
v = 0;
return int_ret(v);
}
STATIC int
f_float()
{
register object_t *o;
register double v;
extern double strtod();
if (NARGS() != 1)
return argcount(1);
o = ARG(0);
if (isfloat(o))
return loose_ret(o);
else if (isstring(o))
v = strtod(stringof(o)->s_chars, NULL);
else if (isint(o))
v = (double)intof(o)->i_value;
else
v = 0;
return obj_ret(objof(new_float(v)));
}
STATIC int
f_num()
{
register object_t *o;
register double f;
register long i;
char *s;
extern double strtod();
char n[30];
if (NARGS() != 1)
return argcount(1);
o = ARG(0);
if (isfloat(o) || isint(o))
return loose_ret(o);
else if (isstring(o))
{
i = strtol(stringof(o)->s_chars, &s, 0);
if (*s == '\0')
return int_ret(i);
f = strtod(stringof(o)->s_chars, &s);
if (*s == '\0')
return obj_ret(objof(new_float(f)));
}
sprintf(buf, "%s is not a number", objname(n, o));
error = buf;
return 1;
}
STATIC int
f_string()
{
register object_t *o;
if (NARGS() != 1)
return argcount(1);
o = ARG(0);
if (isstring(o))
return loose_ret(o);
if (isint(o))
sprintf(buf, "%ld", intof(o)->i_value);
else if (isfloat(o))
sprintf(buf, "%g", floatof(o)->f_value);
else
sprintf(buf, "<%s>", o->o_type->t_name);
return str_ret(buf);
}
STATIC int
f_eq()
{
object_t *o1;
object_t *o2;
if (typecheck("oo", &o1, &o2))
return 1;
if (o1 == o2)
return loose_ret(objof(o_one));
return loose_ret(objof(o_zero));
}
STATIC int
f_push()
{
array_t *s;
object_t *o;
if (typecheck("ao", &s, &o))
return 1;
if (objof(s)->o_flags & O_ATOM)
{
error = "attempt to push atomic array";
return 1;
}
if (pushcheck(s, 1))
return 1;
*s->a_top++ = o;
return loose_ret(o);
}
STATIC int
f_pop()
{
array_t *s;
if (typecheck("a", &s))
return 1;
if (objof(s)->o_flags & O_ATOM)
{
error = "attempt to pop atomic array";
return 1;
}
if (popcheck(s, 1))
return loose_ret(objof(&o_null));
return loose_ret(*--s->a_top);
}
STATIC int
f_top()
{
array_t *s;
long n = 0;
switch (NARGS())
{
case 1:
if (typecheck("a", &s))
return 1;
break;
default:
if (typecheck("ai", &s, &n))
return 1;
if (n > 0)
goto retnull;
if (popcheck(s, 1-n))
goto retnull;
}
if (popcheck(s, 1+n))
goto retnull;
return loose_ret(s->a_top[-1+n]);
retnull:
return loose_ret(objof(&o_null));
}
STATIC int
f_parse()
{
object_t *o;
file_t *f;
struct_t *s; /* Statics. */
struct_t *a; /* Autos. */
switch (NARGS())
{
case 1:
if (typecheck("o", &o))
return 1;
if ((a = new_struct()) == NULL)
return 1;
if ((a->s_super = s = new_struct()) == NULL)
return 1;
loose(s);
s->s_super = structof(v_top[-1])->s_super;
break;
default:
if (typecheck("od", &o, &a))
return 1;
got(a);
break;
}
if (isstring(o))
{
if ((f = sopen(stringof(o)->s_chars, stringof(o)->s_nchars)) == NULL)
{
loose(a);
return 1;
}
f->f_name = get_cname("");
}
else if (isfile(o))
f = fileof(o);
else
{
loose(a);
return argerror(0);
}
if (parse_module(f, a) < 0)
goto fail;
if (isstring(o))
loose(f);
return obj_ret(objof(a));
fail:
if (isstring(o))
loose(f);
loose(a);
return 1;
}
STATIC int
f_include()
{
string_t *filename;
struct_t *a;
int rc;
file_t *f;
switch (NARGS())
{
case 1:
if (typecheck("o", &filename))
return 1;
a = structof(v_top[-1]);
got(a);
break;
case 2:
if (typecheck("od", &filename, &a))
return 1;
got(a);
break;
default:
return argcount(2);
}
if (!isstring(objof(filename)))
{
loose(a);
return argerror(0);
}
if ((error = ici_call("fopen", "o=o", &f, filename)) != NULL)
{
loose(a);
return 1;
}
rc = parse_module(f, a);
ici_call("close", "o", f);
if (rc < 0)
{
loose(a);
return 1;
}
return loose_ret(objof(a));
}
/*
* This calls the called function directly, after putting the args on
* the stack.
*/
STATIC int
f_call()
{
object_t *o;
object_t *aa;
int nargs;
if (typecheck("oo", &o, &aa))
return 1;
o_top -= 3; /* Two args plus us. */
if (!isarray(aa))
{
if (!isnull(aa))
return argerror(1);
nargs = 0;
}
else
{
object_t **a;
/*
* We include an extra 80 in our pushcheck, see start of ici_evaluate().
*/
nargs = arrayof(aa)->a_top - arrayof(aa)->a_base;
if (pushcheck(os, nargs + 80))
return 1;
for (a = arrayof(aa)->a_top - 1; a >= arrayof(aa)->a_base; --a)
*o_top++ = *a;
}
if (pushcheck(os, 1))
return 1;
*o_top++ = o;
x_top[-1] = objof(new_op(NULL, OP_CALL, nargs));
loose(x_top[-1]);
return op_call();
}
STATIC int
f_fail()
{
char *s;
if (typecheck("s", &s))
return 1;
if (chkbuf(strlen(s)))
return 1;
strcpy(buf, s);
error = buf;
return 1;
}
STATIC int
f_exit()
{
object_t *rc;
long status;
switch (NARGS())
{
case 0:
rc = objof(&o_null);
break;
case 1:
if (typecheck("o", &rc))
return 1;
break;
default:
return argcount(1);
}
if (isint(rc))
status = (int)intof(rc)->i_value;
else if (rc == objof(&o_null))
status = 0;
else if (isstring(rc))
{
if (stringof(rc)->s_nchars == 0)
status = 0;
else
{
fprintf(stderr, "exit: %s\n", stringof(rc)->s_chars);
status = 1;
}
}
else
{
return argerror(0);
}
wrapup();
exit(status);
/*NOTREACHED*/
}
#ifndef NO_BACKWARDS_COMPATIBILITY
STATIC int
f_smash()
{
char *s;
char *delim;
register char **p;
register array_t *sa;
register char **strs;
if (typecheck("ss", &s, &delim))
return 1;
if (delim[0] == 0)
{
error = "bad delimiter string";
return 1;
}
if ((strs = smash(s, delim[0])) == NULL)
return 1;
if ((sa = new_array()) == NULL)
goto fail;
if (pushcheck(sa, nptrs(strs)))
goto fail;
for (p = strs; *p != NULL; ++p)
{
if ((*sa->a_top = objof(get_cname(*p))) == NULL)
goto fail;
++sa->a_top;
}
zfree((char *)strs);
return obj_ret(objof(sa));
fail:
if (sa != NULL)
loose(sa);
zfree((char *)strs);
return 1;
}
#endif
STATIC int
f_vstack()
{
return obj_ret(copy(vs));
}
STATIC int
f_tochar()
{
long i;
if (typecheck("i", &i))
return 1;
buf[0] = i;
return obj_ret(objof(new_name(buf, 1)));
}
STATIC int
f_toint()
{
char *s;
if (typecheck("s", &s))
return 1;
return int_ret((long)(s[0] & 0xFF));
}
STATIC int
f_rand()
{
static long seed = 1;
if (NARGS() >= 1)
{
if (typecheck("i", &seed))
return 1;
}
seed = seed * 1103515245 + 12345;
return obj_ret(objof(new_float(((seed >> 16) & 0x7FFF) / 32767.0)));
}
STATIC int
f_interval()
{
object_t *o;
long start;
long length;
long nel;
register string_t *s = 0; /* init to shut up compiler */
register array_t *a = 0; /* init to shut up compiler */
register array_t *a1;
if (typecheck("oi*", &o, &start))
return 1;
length = -1;
if (NARGS() > 2)
{
if (!isint(ARG(2)))
return argerror(2);
if ((length = intof(ARG(2))->i_value) < 0)
argerror(2);
}
switch (o->o_tcode)
{
case TC_STRING:
s = stringof(o);
nel = s->s_nchars;
break;
case TC_ARRAY:
a = arrayof(o);
nel = a->a_top - a->a_base;
break;
default:
return argerror(0);
}
if (start < 0)
{
if ((start += nel) < 0)
start = 0;
}
else if (start > nel)
start = nel;
if (length < 0)
length = nel;
if (start + length > nel)
length = nel - start;
if (o->o_tcode == TC_STRING)
{
return obj_ret(objof(new_name(s->s_chars + start, length)));
}
else
{
if ((a1 = new_array()) == NULL)
return 1;
if (pushcheck(a1, length))
{
loose(a1);
return 1;
}
memcpy((char *)a1->a_base, (char *)(a->a_base + start),
length * sizeof(object_t *));
a1->a_top += length;
return obj_ret(objof(a1));
}
}
STATIC int
f_explode()
{
register int i;
char *s;
array_t *x;
if (typecheck("s", &s))
return 1;
if ((x = new_array()) == NULL)
return 1;
if (pushcheck(x, i = stringof(ARG(0))->s_nchars))
{
loose(x);
return 1;
}
while (--i >= 0)
{
if ((*x->a_top = objof(new_int(*s++ & 0xFFL))) == NULL)
{
loose(x);
return 1;
}
loose(*x->a_top);
++x->a_top;
}
return obj_ret(objof(x));
}
STATIC int
f_implode()
{
array_t *a;
register int i;
register object_t **o;
if (typecheck("a", &a))
return 1;
i = 0;
for (o = a->a_base; o < a->a_top; ++o)
{
switch ((*o)->o_tcode)
{
case TC_INT:
if (chkbuf(i))
return 1;
buf[i++] = intof(*o)->i_value;
break;
case TC_STRING:
if (chkbuf(i + stringof(*o)->s_nchars))
return 1;
memcpy(&buf[i], stringof(*o)->s_chars, stringof(*o)->s_nchars);
i += stringof(*o)->s_nchars;
break;
}
}
return obj_ret(objof(new_name(buf, i)));
}
STATIC int
f_sopen()
{
file_t *f;
char *str;
char *mode;
mode = "r";
if (typecheck(NARGS() > 1 ? "ss" : "s", &str, &mode))
return 1;
if (strcmp(mode, "r") != 0 && strcmp(mode, "rb") != 0)
{
chkbuf(strlen(mode) + 50);
sprintf(buf, "attempt to use mode \"%s\" in sopen()", mode);
error = buf;
return 1;
}
if ((f = sopen(str, stringof(ARG(0))->s_nchars)) == NULL)
return 1;
f->f_name = get_cname("");
return obj_ret(objof(f));
}
STATIC int
f_mopen()
{
mem_t *mem;
file_t *f;
char *mode;
if (typecheck("os", &mem, &mode))
{
if (typecheck("o", &mem))
return 1;
mode = "r";
}
if (!ismem(objof(mem)))
return argerror(0);
if (strcmp(mode, "r") && strcmp(mode, "rb"))
{
error = "bad open mode for mopen";
return 1;
}
if (mem->m_accessz != 1)
{
error = "memory object must have access size of 1 to be opened";
return 1;
}
if ((f = sopen(mem->m_base, mem->m_length)) == NULL)
return 1;
f->f_name = get_cname("");
return obj_ret(objof(f));
}
int
f_sprintf()
{
char *fmt;
register char *p;
register int i; /* Where we are up to in buf. */
register int j;
int which;
int nargs;
char subfmt[40]; /* %...? portion of string. */
int stars[2]; /* Precision and field widths. */
int nstars;
int gotl; /* Have a long int flag. */
long ivalue;
double fvalue;
char *svalue;
object_t **o; /* Argument pointer. */
file_t *file;
extern char *strchr();
#ifdef BAD_PRINTF_RETVAL
#define IPLUSEQ
#else
#define IPLUSEQ i +=
#endif
which = (int)CF_ARG1(); /* sprintf, printf, fprintf */
if (which != 0 && NARGS() > 0 && isfile(ARG(0)))
{
which = 2;
if (typecheck("us*", &file, &fmt))
return 1;
o = ARGS() - 2;
nargs = NARGS() - 2;
}
else
{
if (typecheck("s*", &fmt))
return 1;
o = ARGS() - 1;
nargs = NARGS() - 1;
}
p = fmt;
i = 0;
while (*p != '\0')
{
if (*p != '%')
{
if (chkbuf(i))
return 1;
buf[i++] = *p++;
continue;
}
nstars = 0;
gotl = 0;
subfmt[0] = *p++;
j = 1;
while (*p != '\0' && strchr("diouxXfeEgGcs%", *p) == NULL)
{
if (*p == '*')
++nstars;
else if (*p == 'l')
gotl = 1;
subfmt[j++] = *p++;
}
if (gotl == 0 && strchr("diouxXc", *p) != NULL)
subfmt[j++] = 'l';
subfmt[j++] = *p;
subfmt[j++] = '\0';
if (nstars > 2)
nstars = 2;
stars[0] = 0;
stars[1] = 0;
for (j = 0; j < nstars; ++j)
{
if (nargs <= 0)
goto lacking;
if (!isint(*o))
goto type;
stars[j] = intof(*o)->i_value;
--o;
--nargs;
}
switch (*p++)
{
case 'd':
case 'i':
case 'o':
case 'u':
case 'x':
case 'X':
case 'c':
if (nargs <= 0)
goto lacking;
if (isint(*o))
ivalue = intof(*o)->i_value;
else if (isfloat(*o))
ivalue = floatof(*o)->f_value;
else
goto type;
if (chkbuf(i + 30)) /* Worst case. */
return 1;
switch (nstars)
{
case 0:
IPLUSEQ sprintf(&buf[i], subfmt, ivalue);
break;
case 1:
IPLUSEQ sprintf(&buf[i], subfmt, stars[0], ivalue);
break;
case 2:
IPLUSEQ sprintf(&buf[i], subfmt, stars[0], stars[1], ivalue);
break;
}
--o;
--nargs;
break;
case 's':
if (nargs <= 0)
goto lacking;
if (!isstring(*o))
goto type;
svalue = stringof(*o)->s_chars;
if (chkbuf(i + stringof(*o)->s_nchars + stars[0] + stars[1]))
return 1;
switch (nstars)
{
case 0:
IPLUSEQ sprintf(&buf[i], subfmt, svalue);
break;
case 1:
IPLUSEQ sprintf(&buf[i], subfmt, stars[0], svalue);
break;
case 2:
IPLUSEQ sprintf(&buf[i], subfmt, stars[0], stars[1], svalue);
break;
}
--o;
--nargs;
break;
case 'f':
case 'e':
case 'E':
case 'g':
case 'G':
if (nargs <= 0)
goto lacking;
if (isint(*o))
fvalue = intof(*o)->i_value;
else if (isfloat(*o))
fvalue = floatof(*o)->f_value;
else
goto type;
if (chkbuf(i + 40)) /* Worst case. */
return 1;
switch (nstars)
{
case 0:
IPLUSEQ sprintf(&buf[i], subfmt, fvalue);
break;
case 1:
IPLUSEQ sprintf(&buf[i], subfmt, stars[0], fvalue);
break;
case 2:
IPLUSEQ sprintf(&buf[i], subfmt, stars[0], stars[1], fvalue);
break;
}
--o;
--nargs;
break;
case '%':
if (chkbuf(i))
return 1;
buf[i++] = '%';
continue;
}
#ifdef BAD_PRINTF_RETVAL
i = strlen(buf); /* BSD sprintf doesn't return usual value. */
#endif
}
buf[i] = '\0';
switch (which)
{
case 1: /* printf */
if ((file = need_stdout()) == NULL)
return 1;
case 2: /* fprintf */
if (objof(file)->o_flags & F_CLOSED)
{
error = "write to closed file";
return 1;
}
(*file->f_type->ft_write)(buf, i, file->f_file);
return int_ret((long)i);
default: /* sprintf */
return str_ret(buf);
}
type:
sprintf(buf, "attempt to use a %s with a \"%s\" format in sprintf",
(*o)->o_type->t_name, subfmt);
error = buf;
return 1;
lacking:
error = "not enoughs args to sprintf";
return 1;
}
STATIC int
f_currentfile()
{
object_t **o;
for (o = x_top - 1; o >= xs->a_base; --o)
{
if (isparse(*o))
return loose_ret(objof(parseof(*o)->p_file));
}
return loose_ret(objof(&o_null));
}
STATIC int
f_del()
{
struct_t *s;
object_t *o;
if (typecheck("do", &s, &o))
return 1;
unassign_struct(s, o);
return loose_ret(objof(&o_null));
}
STATIC int
super_loop(s)
struct_t *s;
{
set_t *set;
if ((set = new_set()) == NULL)
return 1;
while (s->s_super != NULL)
{
if (assign(set, s, objof(o_one)))
goto fail;
if (fetch(set, objof(s->s_super)) == objof(o_one))
{
error = "cycle in structure super chain";
goto fail;
}
s = s->s_super;
}
loose(set);
return 0;
fail:
loose(set);
return 1;
}
STATIC int
f_super()
{
struct_t *s;
struct_t *newsuper;
struct_t *oldsuper;
if (typecheck("d*", &s))
return 1;
newsuper = oldsuper = s->s_super;
if (NARGS() >= 2)
{
if (objof(s)->o_flags & O_ATOM)
{
error = "attempt to set super of an atomic struct";
return 1;
}
if (isnull(ARG(1)))
newsuper = NULL;
else if (isstruct(ARG(1)))
newsuper = structof(ARG(1));
else
return argerror(1);
NEXT_VSVER;
}
s->s_super = newsuper;
if (super_loop(s))
{
s->s_super = oldsuper;
return 1;
}
if (oldsuper == NULL)
return loose_ret(objof(&o_null));
return loose_ret(objof(oldsuper));
}
STATIC int
f_scope()
{
struct_t *s;
s = structof(v_top[-1]);
if (NARGS() > 0)
{
if (typecheck("d", &v_top[-1]))
return 1;
}
return loose_ret(objof(s));
}
STATIC int
f_isatom()
{
object_t *o;
if (typecheck("o", &o))
return 1;
if (o->o_flags & O_ATOM)
return loose_ret(objof(o_one));
else
return loose_ret(objof(o_zero));
}
STATIC int
f_alloc()
{
long length;
int accessz;
char *p;
if (typecheck("i*", &length))
return 1;
if (length < 0)
{
error = "attempt to allocate negative amount";
return 1;
}
if (NARGS() >= 2)
{
if
(
!isint(ARG(1))
||
(
(accessz = intof(ARG(1))->i_value) != 1
&&
accessz != 2
&&
accessz != 4
)
)
return argerror(1);
}
else
accessz = 1;
if ((p = zalloc(length * accessz)) == NULL)
return 1;
memset(p, 0, length * accessz);
return obj_ret(objof(new_mem(p, (unsigned long)length, accessz, ici_free)));
}
STATIC int
f_mem()
{
long base;
long length;
int accessz;
if (typecheck("ii*", &base, &length))
return 1;
if (NARGS() >= 3)
{
if
(
!isint(ARG(2))
||
(
(accessz = intof(ARG(2))->i_value) != 1
&&
accessz != 2
&&
accessz != 4
)
)
return argerror(2);
}
else
accessz = 1;
return obj_ret(objof(new_mem((char *)base, (unsigned long)length, accessz, NULL)));
}
STATIC int
f_assign()
{
struct_t *s;
struct_t *super;
object_t *k;
object_t *v;
int r;
if (typecheck("doo", &s, &k, &v))
return 1;
if ((super = s->s_super) != NULL)
got(super);
s->s_super = NULL;
r = assign(s, k, v);
if ((s->s_super = super) != NULL)
loose(super);
if (r)
return 1;
return loose_ret(v);
}
STATIC int
f_fetch()
{
struct_t *s;
struct_t *super;
object_t *k;
object_t *v;
if (typecheck("do", &s, &k))
return 1;
if ((super = s->s_super) != NULL)
got(super);
s->s_super = NULL;
v = fetch(s, k);
if ((s->s_super = super) != NULL)
loose(super);
return loose_ret(v);
}
#ifndef NOWAITFOR
STATIC int
f_waitfor()
{
register object_t **e;
int nargs;
fd_set readfds;
struct timeval timeval;
struct timeval *tv;
double to;
int nfds;
int i;
#ifndef fileno
extern int fileno();
#endif
if (NARGS() == 0)
return loose_ret(objof(o_zero));
tv = NULL;
nfds = 0;
FD_ZERO(&readfds);
to = 0.0; /* Stops warnings, not required. */
for (nargs = NARGS(), e = ARGS(); nargs > 0; --nargs, --e)
{
if (isfile(*e))
{
/*
* If the ft_getch routine of the file is the real stdio fgetc,
* we can assume the file is a real stdio stream file, then
* we also assume we can use fileno on it.
*/
if (fileof(*e)->f_type->ft_getch == fgetc)
{
setvbuf((FILE *)fileof(*e)->f_file, NULL, _IONBF, 0);
i = fileno((FILE *)fileof(*e)->f_file);
FD_SET(i, &readfds);
if (i >= nfds)
nfds = i + 1;
}
else
return loose_ret(*e);
}
else if (isint(*e))
{
if (tv == NULL || to > intof(*e)->i_value / 1000.0)
{
to = intof(*e)->i_value / 1000.0;
tv = &timeval;
}
}
else if (isfloat(*e))
{
if (tv == NULL || to > floatof(*e)->f_value)
{
to = floatof(*e)->f_value;
tv = &timeval;
}
}
else
return argerror(ARGS() - e);
}
if (tv != NULL)
{
tv->tv_sec = to;
tv->tv_usec = (to - tv->tv_sec) * 1000000.0;
}
switch (select(nfds, &readfds, NULL, NULL, tv))
{
case -1:
error = "could not select";
return 1;
case 0:
return loose_ret(objof(o_zero));
}
for (nargs = NARGS(), e = ARGS(); nargs > 0; --nargs, --e)
{
if (!isfile(*e))
continue;
if (fileof(*e)->f_type->ft_getch == fgetc)
{
i = fileno((FILE *)fileof(*e)->f_file);
if (FD_ISSET(i, &readfds))
return loose_ret(*e);
}
}
error = "no file selected";
return 1;
}
#endif
STATIC int
f_gettoken()
{
file_t *f;
string_t *s;
unsigned char *seps;
int nseps;
char *file;
int (*get)();
int c;
int i;
int j;
seps = (unsigned char *) " \t\n";
nseps = 3;
switch (NARGS())
{
case 0:
if ((f = need_stdin()) == NULL)
return 1;
break;
case 1:
if (typecheck("o", &f))
return 1;
if (isstring(objof(f)))
{
if ((f = sopen(stringof(f)->s_chars, stringof(f)->s_nchars)) == NULL)
return 1;
loose(f);
}
else if (!isfile(objof(f)))
return argerror(0);
break;
default:
if (typecheck("oo", &f, &s))
return 1;
if (isstring(objof(f)))
{
if ((f = sopen(stringof(f)->s_chars, stringof(f)->s_nchars)) == NULL)
return 1;
loose(f);
}
else if (!isfile(objof(f)))
return argerror(0);
if (!isstring(objof(s)))
return argerror(1);
seps = (unsigned char *)s->s_chars;
nseps = s->s_nchars;
break;
}
get = f->f_type->ft_getch;
file = f->f_file;
do
{
c = (*get)(file);
if (c == EOF)
return loose_ret(objof(&o_null));
for (i = 0; i < nseps; ++i)
{
if (c == seps[i])
break;
}
} while (i != nseps);
j = 0;
do
{
chkbuf(j);
buf[j++] = c;
c = (*get)(file);
if (c == EOF)
break;
for (i = 0; i < nseps; ++i)
{
if (c == seps[i])
{
(*f->f_type->ft_ungetch)(c, file);
break;
}
}
} while (i == nseps);
if ((s = new_name(buf, j)) == NULL)
return 1;
return obj_ret(objof(s));
}
STATIC int
f_gettokens()
{
file_t *f;
string_t *s;
unsigned char *terms;
int nterms;
unsigned char *seps;
int nseps;
unsigned char *delims = 0; /* init to shut up compiler */
int ndelims;
int hardsep;
unsigned char sep;
char *file;
array_t *a;
int (*get)();
int c;
int i;
int j = 0; /* init to shut up compiler */
int state;
int what;
int loose_it = 0;
seps = (unsigned char *)" \t";
nseps = 2;
hardsep = 0;
terms = (unsigned char *)"\n";
nterms = 1;
ndelims = 0;
switch (NARGS())
{
case 0:
if ((f = need_stdin()) == NULL)
return 1;
break;
case 1:
if (typecheck("o", &f))
return 1;
if (isstring(objof(f)))
{
if ((f = sopen(stringof(f)->s_chars, stringof(f)->s_nchars)) == NULL)
return 1;
loose_it = 1;
}
else if (!isfile(objof(f)))
return argerror(0);
break;
case 2:
case 3:
case 4:
if (typecheck("oo*", &f, &s))
return 1;
if (isstring(objof(f)))
{
if ((f = sopen(stringof(f)->s_chars, stringof(f)->s_nchars)) == NULL)
return 1;
loose_it = 1;
}
else if (!isfile(objof(f)))
return argerror(0);
if (isint(objof(s)))
{
sep = intof(objof(s))->i_value;
hardsep = 1;
seps = (unsigned char *)&sep;
nseps = 1;
}
else if (isstring(objof(s)))
{
seps = (unsigned char *)s->s_chars;
nseps = s->s_nchars;
}
else
{
if (loose_it)
loose(f);
return argerror(1);
}
if (NARGS() > 2)
{
if (!isstring(ARG(2)))
{
if (loose_it)
loose(f);
return argerror(2);
}
terms = (unsigned char *)stringof(ARG(2))->s_chars;
nterms = stringof(ARG(2))->s_nchars;
if (NARGS() > 3)
{
if (!isstring(ARG(3)))
{
if (loose_it)
loose(f);
return argerror(3);
}
delims = (unsigned char *)stringof(ARG(3))->s_chars;
ndelims = stringof(ARG(3))->s_nchars;
}
}
break;
default:
return argcount(3);
}
get = f->f_type->ft_getch;
file = f->f_file;
#define S_IDLE 0
#define S_INTOK 1
#define W_EOF 0
#define W_SEP 1
#define W_TERM 2
#define W_TOK 3
#define W_DELIM 4
state = S_IDLE;
if ((a = new_array()) == NULL)
goto fail;
for (;;)
{
/*
* Get the next character and classify it.
*/
if ((c = (*get)(file)) == EOF)
{
what = W_EOF;
goto got_what;
}
for (i = 0; i < nseps; ++i)
{
if (c == seps[i])
{
what = W_SEP;
goto got_what;
}
}
for (i = 0; i < nterms; ++i)
{
if (c == terms[i])
{
what = W_TERM;
goto got_what;
}
}
for (i = 0; i < ndelims; ++i)
{
if (c == delims[i])
{
what = W_DELIM;
goto got_what;
}
}
what = W_TOK;
got_what:
/*
* Act on state and current character classification.
*/
switch ((state << 8) + what)
{
case (S_IDLE << 8) + W_EOF:
if (loose_it)
loose(f);
if (a->a_top == a->a_base)
{
loose(a);
return loose_ret(objof(&o_null));
}
return obj_ret(objof(a));
case (S_IDLE << 8) + W_TERM:
if (!hardsep)
{
if (loose_it)
loose(f);
return obj_ret(objof(a));
}
j = 0;
case (S_INTOK << 8) + W_EOF:
case (S_INTOK << 8) + W_TERM:
if (pushcheck(a, 1))
goto fail;
if ((s = new_name(buf, j)) == NULL)
goto fail;
*a->a_top++ = objof(s);
if (loose_it)
loose(f);
loose(s);
return obj_ret(objof(a));
case (S_IDLE << 8) + W_SEP:
if (!hardsep)
break;
j = 0;
case (S_INTOK << 8) + W_SEP:
if (pushcheck(a, 1))
goto fail;
if ((s = new_name(buf, j)) == NULL)
goto fail;
*a->a_top++ = objof(s);
loose(s);
if (hardsep)
{
j = 0;
state = S_INTOK;
}
else
state = S_IDLE;
break;
case (S_INTOK << 8) + W_DELIM:
if (pushcheck(a, 1))
goto fail;
if ((s = new_name(buf, j)) == NULL)
goto fail;
*a->a_top++ = objof(s);
loose(s);
case (S_IDLE << 8) + W_DELIM:
if (pushcheck(a, 1))
goto fail;
buf[0] = c;
if ((s = new_name(buf, 1)) == NULL)
goto fail;
*a->a_top++ = objof(s);
loose(s);
j = 0;
state = S_IDLE;
break;
case (S_IDLE << 8) + W_TOK:
j = 0;
state = S_INTOK;
case (S_INTOK << 8) + W_TOK:
if (chkbuf(j))
goto fail;
buf[j++] = c;
}
}
fail:
if (loose_it)
loose(f);
if (a != NULL)
loose(a);
return 1;
}
STATIC string_t *
do_sub(str, re, repl)
string_t *str;
regexp_t *re;
char *repl;
{
char *dst;
int normal;
char *p;
string_t *rc;
int len;
char *d;
/*
* Match the regexp against the input string.
*/
if (!regexec(re->r_re, stringof(str)->s_chars))
return NULL;
/*
* The string is divided into three parts. The bit before the matched
* regexp, the matched section and anything that follows. We want to
* determine the size of the actual output string so we can allocate
* some space for it.
*/
#define START(n) re->r_re->startp[n]
#define END(n) re->r_re->endp[n]
len = stringof(str)->s_nchars - (END(0) - START(0));
/*
* Determine size of matched area. This depends on the replacement
* text. If there are any \& or \nnn sequences these must be
* replaced by the appropriate section of the input string.
*/
for (normal = 1, p = repl; *p != 0; ++p)
{
int c = *p;
if (normal)
{
if (c == '\\')
normal = 0;
else
++len;
}
else
{
normal = 1;
if (!isdigit(c))
len += 2;
else
{
c -= '0';
if (START(c) != NULL)
len += END(c) - START(c);
}
}
}
/*
* Now get that much space and stuff it with the string.
*/
if ((dst = zalloc(len)) == NULL)
return (string_t *)-1;
memcpy(dst, stringof(str)->s_chars, START(0) - stringof(str)->s_chars);
d = &dst[START(0) - stringof(str)->s_chars];
for (normal = 1, p = repl; *p != 0; ++p)
{
int c = *p;
if (normal)
{
if (c == '\\')
normal = 0;
else
*d++ = c;
}
else
{
normal = 1;
c -= '0';
if (!isdigit(c))
{
*d++ = '\\';
*d++ = c;
}
else
{
strncpy(d, START(c), END(c) - START(c));
d += END(c) - START(c);
}
}
}
*d = 0;
strncpy(d, END(0), (stringof(str)->s_chars + stringof(str)->s_nchars) - END(0) + 1);
rc = new_cname(dst);
zfree(dst);
if (rc == NULL)
return (string_t *)-1;
return rc;
#undef START
#undef END
}
STATIC int
f_sub()
{
object_t *str;
object_t *o;
regexp_t *re;
char *repl;
string_t *rc;
/*
* Get the ICI arguments.
*/
if (typecheck("oos", &str, &o, &repl))
return 1;
if (!isstring(str))
return argerror(0);
if (isregexp(o))
re = regexpof(o);
else if (!isstring(o))
return argerror(1);
else if ((re = new_regexp(stringof(o)->s_chars)) == NULL)
return 1;
if ((rc = do_sub(str, re, repl)) == NULL)
rc = stringof(str);
else if (rc == (string_t*)-1)
return 1;
return loose_ret(objof(rc));
}
STATIC int
f_gsub()
{
object_t *str;
object_t *o;
regexp_t *re;
char *repl;
string_t *rc;
/*
* Get the ICI arguments.
*/
if (typecheck("oos", &str, &o, &repl))
return 1;
if (!isstring(str))
return argerror(0);
if (isregexp(o))
re = regexpof(o);
else if (!isstring(o))
return argerror(1);
else if ((re = new_regexp(stringof(o)->s_chars)) == NULL)
return 1;
do
{
if ((rc = do_sub(str, re, repl)) == (string_t *)-1)
return 1;
else if (rc != NULL)
str = objof(rc);
}
while (rc != NULL);
return loose_ret(objof(str));
}
/*
* sort(array, cmp)
*/
static int
f_sort()
{
array_t *a;
object_t **base;
long n;
func_t *f;
long cmp;
long k; /* element added or removed */
long p; /* place in heap */
long q; /* place in heap */
long l; /* left child */
long r; /* right child */
object_t *o; /* object used for swapping */
/*
* Relations within heap.
*/
#define PARENT(i) (((i) - 1) >> 1)
#define LEFT(i) ((i) + (i) + 1)
#define RIGHT(i) ((i) + (i) + 2)
/*
* Macro for swapping elements.
*/
#define SWAP(a, b) {o = base[a]; base[a] = base[b]; base[b] = o;}
#define CMP(rp, a, b) ici_func(objof(f), "i=oo", rp, base[a], base[b])
if (typecheck("ao", &a, &f))
return 1;
if (!isfunc(objof(f)))
return argerror(1);
if (objof(a)->o_flags & O_ATOM)
{
error = "attempt to sort an atomic array";
return 1;
}
base = a->a_base;
n = a->a_top - base;
/*
* Shuffle heap.
*/
for (k = 1; k < n; ++k)
{
p = k;
while (p != 0)
{
q = PARENT(p);
if (CMP(&cmp, p, q) != NULL)
goto fail;
if (cmp <= 0)
break;
SWAP(p, q);
p = q;
}
}
/*
* Keep taking elements off heap and re-shuffling.
*/
for (k = n - 1; k > 0; --k)
{
SWAP(0, k);
p = 0;
while (1)
{
l = LEFT(p);
if (l >= k)
break;
r = RIGHT(p);
if (r >= k)
{
if (CMP(&cmp, l, p) != NULL)
goto fail;
if (cmp <= 0)
break;
SWAP(l, p);
p = l;
}
else
{
if (CMP(&cmp, l, p) != NULL)
goto fail;
if (cmp <= 0)
{
if (CMP(&cmp, r, p) != NULL)
goto fail;
if (cmp <= 0)
break;
SWAP(r, p);
p = r;
}
else
{
if (CMP(&cmp, r, l) != NULL)
goto fail;
if (cmp <= 0)
{
SWAP(l, p);
p = l;
}
else
{
SWAP(r, p);
p = r;
}
}
}
}
}
return loose_ret(objof(&o_null));
fail:
return 1;
#undef PARENT
#undef LEFT
#undef RIGHT
#undef SWAP
}
f_reclaim()
{
ici_reclaim();
return loose_ret(objof(&o_null));
}
int
def_cfuncs(cf)
register cfunc_t *cf;
{
register string_t *n;
while (cf->cf_name != NULL)
{
if ((n = new_cname(cf->cf_name)) == NULL)
return 1;
if (assign(structof(v_top[-1])->s_super, n, cf))
{
loose(n);
return 1;
}
loose(n);
++cf;
}
return 0;
}
cfunc_t std_cfuncs[] =
{
{CF_OBJ, "array", f_array},
{CF_OBJ, "copy", f_copy},
{CF_OBJ, "exit", f_exit},
{CF_OBJ, "fail", f_fail},
{CF_OBJ, "float", f_float},
{CF_OBJ, "int", f_int},
{CF_OBJ, "eq", f_eq},
{CF_OBJ, "parse", f_parse},
{CF_OBJ, "regexp", f_regexp},
{CF_OBJ, "sizeof", f_nels}, /* Phaseing out, use nels. */
{CF_OBJ, "string", f_string},
{CF_OBJ, "struct", f_struct},
{CF_OBJ, "set", f_set},
{CF_OBJ, "typeof", f_typeof},
{CF_OBJ, "push", f_push},
{CF_OBJ, "pop", f_pop},
{CF_OBJ, "call", f_call},
{CF_OBJ, "keys", f_keys},
{CF_OBJ, "smash", f_smash},
{CF_OBJ, "vstack", f_vstack},
{CF_OBJ, "tochar", f_tochar},
{CF_OBJ, "toint", f_toint},
{CF_OBJ, "rand", f_rand},
{CF_OBJ, "interval", f_interval},
{CF_OBJ, "explode", f_explode},
{CF_OBJ, "implode", f_implode},
{CF_OBJ, "sopen", f_sopen},
{CF_OBJ, "mopen", f_mopen},
{CF_OBJ, "sprintf", f_sprintf},
{CF_OBJ, "currentfile", f_currentfile},
{CF_OBJ, "del", f_del},
{CF_OBJ, "alloc", f_alloc},
{CF_OBJ, "mem", f_mem},
{CF_OBJ, "nels", f_nels},
{CF_OBJ, "super", f_super},
{CF_OBJ, "scope", f_scope},
{CF_OBJ, "isatom", f_isatom},
{CF_OBJ, "gettoken", f_gettoken},
{CF_OBJ, "gettokens", f_gettokens},
{CF_OBJ, "num", f_num},
{CF_OBJ, "assign", f_assign},
{CF_OBJ, "fetch", f_fetch},
#ifndef NOMATH
{CF_OBJ, "sin", f_math, (int (*)())sin, "f=n"},
{CF_OBJ, "cos", f_math, (int (*)())cos, "f=n"},
{CF_OBJ, "tan", f_math, (int (*)())tan, "f=n"},
{CF_OBJ, "asin", f_math, (int (*)())asin, "f=n"},
{CF_OBJ, "acos", f_math, (int (*)())acos, "f=n"},
{CF_OBJ, "atan", f_math, (int (*)())atan, "f=n"},
{CF_OBJ, "atan2", f_math, (int (*)())atan2, "f=nn"},
{CF_OBJ, "exp", f_math, (int (*)())exp, "f=n"},
{CF_OBJ, "log", f_math, (int (*)())log, "f=n"},
{CF_OBJ, "log10", f_math, (int (*)())log10, "f=n"},
{CF_OBJ, "pow", f_math, (int (*)())pow, "f=nn"},
{CF_OBJ, "sqrt", f_math, (int (*)())sqrt, "f=n"},
{CF_OBJ, "floor", f_math, (int (*)())floor, "f=n"},
{CF_OBJ, "ceil", f_math, (int (*)())ceil, "f=n"},
{CF_OBJ, "fmod", f_math, (int (*)())fmod, "f=nn"},
#endif
#ifndef NOWAITFOR
{CF_OBJ, "waitfor", f_waitfor},
#endif
{CF_OBJ, "top", f_top},
{CF_OBJ, "include", f_include},
{CF_OBJ, "sub", f_sub},
{CF_OBJ, "gsub", f_gsub},
{CF_OBJ, "sort", f_sort},
#ifdef WHOALLOC
{CF_OBJ, "reclaim", f_reclaim},
#endif
{CF_OBJ}
};